package org.lex.splitter.core;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

public class Splitter {
	private static final int DEFAULT_SIZE = 15 * 1024;
	private Logger log = Logger.getLogger(Splitter.class);

	public List<File> split(File input) throws IOException {
		return split(input, DEFAULT_SIZE);
	}

	public List<File> split(File input, int size) throws IOException {
		return split(input, input.getParentFile(), size);
	}

	public List<File> split(File input, File outputFolder) throws IOException {
		return split(input, outputFolder, DEFAULT_SIZE);
	}

	public List<File> split(File input, File outputFolder, int size) throws IOException {
		String name = input.getName();
		log.info("File Name=" + name);
		int end = name.lastIndexOf('.');
		String prefix = name.substring(0, -1 == end ? name.length() : end);

		return split(input, outputFolder, prefix, size);
	}

	public List<File> split(File input, File outputDirectory, String prefix, int size) throws IOException {
		log.info("Input File=" + input);
		log.info("Output Directory=" + outputDirectory);
		log.info("Prefix=" + prefix);
		log.info("size=" + size);

		if (false == outputDirectory.exists() || false == outputDirectory.isDirectory()) {
			log.info("Output Directory not exists, create it");
			boolean success = outputDirectory.mkdirs();
			log.info("Create [" + outputDirectory + "] success? " + success);
		}
		log.info("Open [" + input + "] to read");
		BufferedReader in = new BufferedReader(new FileReader(input));

		char[] buf = new char[size];
		int len = 0;
		int index = 0;
		List<File> files = new ArrayList<File>();
		int indexLength = this.guessIndexLength(input, size);
		log.debug("Index Length=" + indexLength);

		while (-1 != (len = in.read(buf))) {
			File outputFile = createFile(outputDirectory, prefix, indexLength, index);
			log.info("Create split file: " + outputFile);
			BufferedWriter out = new BufferedWriter(new FileWriter(outputFile));
			out.write(buf, 0, len);

			int ch = 0;
			while (-1 != (ch = in.read())) {
				if ('\n' == ch || '\r' == ch) {
					break;
				} else {
					out.write(ch);
				}
			}
			out.flush();
			out.close();
			log.info("Write file=[" + outputFile + "] with " + outputFile.length() + " chars");

			files.add(outputFile);
			index++;
		}
		log.info(files.size() + " files wrote");
		in.close();
		return files;
	}

	private int guessIndexLength(File file, int size) {
		int splitCount = ((int) (file.length() / size) + 1);
		return Integer.toString(splitCount).length();
	}

	private static File createFile(File dir, String prefix, int indexLength, int index) throws IOException {
		File file = new File(dir, prefix + toString(index, indexLength) + ".txt");
		if (false == file.exists() || false == file.isFile()) {
			file.createNewFile();
		}
		return file;
	}

	private static StringBuilder buf = new StringBuilder();

	private static String toString(int value, int length) {
		buf.setLength(0);
		buf.append(value);
		int padding = length - buf.length();
		for (int i = 0; i < padding; i++) {
			buf.insert(0, '0');
		}
		return buf.toString();
	}
}
